
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Practices.RepositoryFactory.CustomPages.UI;
using System.Data;
using System.Configuration;
using SD = Microsoft.Practices.RepositoryFactory.SchemaDiscovery.ObjectModel.Base;
using Microsoft.Practices.RepositoryFactory.SchemaDiscovery;
using Microsoft.Practices.RepositoryFactory.CustomPages.Validators;
using System.Windows;
using System.Globalization;
using Resources=Microsoft.Practices.RepositoryFactory.Properties.Resources;

namespace Microsoft.Practices.RepositoryFactory.CustomPages.Helpers
{
    /// <summary/>
    internal static class NodesHelper
    {
        const string StoredProceduresNodeName = "Stored Procedures";
        const string ViewsNodeName = "Views";
        const string TablesFolderNode = "Tables";
        const string IsNullableValue = "null";
        const string IsNotNullableValue = "not null";

        /// <summary>
        /// Gets the stored procedure nodes.
        /// </summary>
        /// <param name="connectionSettings">The connection settings.</param>
        /// <returns></returns>
        public static System.Windows.Forms.TreeNode GetStoredProcedureNodes(ConnectionStringSettings connectionSettings)
        {
            DbSchemaDiscoverer dbSchemaDiscovery = new DbSchemaDiscoverer(connectionSettings);
            List<SD.StoredProcedure> storedProcedures = dbSchemaDiscovery.DiscoverStoredProcedures();

            if(storedProcedures.Count > 0)
            {
                FolderNode parentNode = new FolderNode(StoredProceduresNodeName);
                storedProcedures.ForEach(new Action<SD.StoredProcedure>(
                    delegate(SD.StoredProcedure storedProcedure)
                    {
                        StoredProcedureNode node = new StoredProcedureNode(storedProcedure);
                        foreach(SD.Parameter parameter in storedProcedure.Parameters)
                        {
                            switch(parameter.Direction)
                            {
                                case ParameterDirection.Input:
                                    node.Nodes.Add(new InputParameterNode(parameter));
                                    break;
                                case ParameterDirection.Output:
                                    node.Nodes.Add(new OutputParameterNode(parameter));
                                    break;
                                case ParameterDirection.InputOutput:
                                    node.Nodes.Add(new InputOutputParameterNode(parameter));
                                    break;
                            }
                        }
                        parentNode.Nodes.Add(node);
                    }
                    ));

                return parentNode;
            }
            else 
            {
                return null;
            }
        }

        /// <summary>
        /// Gets the view nodes.
        /// </summary>
        /// <param name="connectionSettings">The connection settings.</param>
        /// <returns></returns>
        public static System.Windows.Forms.TreeNode GetViewNodes(ConnectionStringSettings connectionSettings)
        {
            DbSchemaDiscoverer dbSchemaDiscovery = new DbSchemaDiscoverer(connectionSettings);
            List<SD.View> views = dbSchemaDiscovery.DiscoverViews();

            if(views.Count > 0)
            {
                FolderNode parentNode = new FolderNode(ViewsNodeName);
                views.ForEach(new Action<SD.View>(
                    delegate(SD.View view)
                    {
                        ViewNode node = new ViewNode(view);
                        foreach(SD.Column col in view.Columns)
                        {
                            int invalidColumns = 0;
                            ColumnNode columnNode = new ColumnNode(col);

                            if(!new ColumnValidator(col).IsValid())
                            {
                                columnNode.ForeColor = System.Drawing.SystemColors.GrayText;
                                columnNode.ToolTipText = Resources.InvalidColumn;
                                invalidColumns++;
                            }

                            node.Nodes.Add(columnNode);

                            if(invalidColumns == node.Nodes.Count)
                            {
                                node.ForeColor = System.Drawing.SystemColors.GrayText;
                                node.ToolTipText = Resources.InvalidTable;
                            }
                        }

                        parentNode.Nodes.Add(node);
                    }
                    ));

                return parentNode;
            }
            else
            {
                return null;
            }
        }

        /// <summary>
        /// Gets the table nodes.
        /// </summary>
        /// <param name="connectionSettings">The connection settings.</param>
        /// <param name="createColumnNodes">if set to <c>true</c> [create column nodes].</param>
        /// <returns></returns>
        public static System.Windows.Forms.TreeNode GetTableNodes(ConnectionStringSettings connectionSettings, bool createColumnNodes)
        {
            DbSchemaDiscoverer dbSchemaDiscovery = new DbSchemaDiscoverer(connectionSettings);

            List<SD.Table> tables = tables = dbSchemaDiscovery.DiscoverTables();

            if(tables.Count > 0)
            {
                FolderNode parentNode = new FolderNode(TablesFolderNode);

                tables.ForEach(new Action<SD.Table>(
                    delegate(SD.Table table)
                    {
                        TableNode node = new TableNode(table);

                        if(createColumnNodes)
                        {
                            int invalidColumns = 0;

                            foreach(SD.Column col in table.Columns)
                            {
                                ColumnNode columnNode = new ColumnNode(col);

                                if(!new ColumnValidator(col).IsValid())
                                {
                                    columnNode.ForeColor = System.Drawing.SystemColors.GrayText;
                                    columnNode.ToolTipText = Resources.InvalidColumn;

                                    invalidColumns++;
                                }
                                
                                node.Nodes.Add(columnNode);
                            }

                            if(invalidColumns == node.Nodes.Count)
                            {
                                node.ForeColor = System.Drawing.SystemColors.GrayText;
                                node.ToolTipText = Resources.InvalidTable;
                            }
                        }
                        else
                        {
                            if(!new TableValidator(table).IsValid())
                            {
                                node.ForeColor = System.Drawing.SystemColors.GrayText;
                                node.ToolTipText = Resources.InvalidTable;
                            }                            
                        }

                        parentNode.Nodes.Add(node);
                    }
                    ));

                return parentNode;
            }
            else
            {
                return null;
            }
        }

        /// <summary>
        /// Checks the nodes.
        /// </summary>
        /// <param name="node">The node.</param>
        /// <param name="check">if set to <c>true</c> [check].</param>
        public static void CheckNodes(System.Windows.Forms.TreeNode node, bool check)
        {
            foreach(System.Windows.Forms.TreeNode nodeTemp in node.Nodes)
            {
                nodeTemp.Checked = check;
                CheckNodes(nodeTemp, check);
            }
        }

        /// <summary>
        /// Ares the sibling nodes checked.
        /// </summary>
        /// <param name="baseNode">The base node.</param>
        /// <returns></returns>
        public static bool AreSiblingNodesChecked(System.Windows.Forms.TreeNode baseNode)
        {
            if(baseNode.Parent != null)
            {
                foreach(System.Windows.Forms.TreeNode node in baseNode.Parent.Nodes)
                {
                    if(node != baseNode && node.Checked)
                    {
                        return true;
                    }
                }
            }

            return false;
        }

        /// <summary>
        /// Verifies the parent.
        /// </summary>
        /// <param name="e">The <see cref="T:System.Windows.Forms.TreeViewEventArgs"/> instance containing the event data.</param>
        public static void VerifyParent(System.Windows.Forms.TreeViewEventArgs e)
        {
            if(e.Node.Parent != null)
            {
                if(!AreSiblingNodesChecked(e.Node))
                {
                    if(e.Node.Parent.Checked)
                    {
                        e.Node.Parent.Checked = e.Node.Checked;
                    }
                }
            }
        }

        /// <summary>
        /// Generates the parameter text.
        /// </summary>
        /// <param name="parameter">The parameter.</param>
        /// <returns></returns>
        public static string GenerateParameterText(SD.Parameter parameter)
        {
            string parameterText;
            string dataType;

            if(parameter.DbDataType.ProviderType == SD.DatabaseType.Char ||
                parameter.DbDataType.ProviderType == SD.DatabaseType.NChar ||
                parameter.DbDataType.ProviderType == SD.DatabaseType.NVarChar ||
                parameter.DbDataType.ProviderType == SD.DatabaseType.VarChar)
            {
                dataType = string.Format(CultureInfo.CurrentCulture, Resources.GenerateParameterTextTwoParams, parameter.DbDataType.ProviderType, parameter.DbDataType.Size);
            }
            else
            {
                dataType = parameter.DbDataType.ProviderType.ToString();
            }

            parameterText = string.Format(CultureInfo.CurrentCulture, Resources.GenerateParameterTextThreeParams, parameter.Name, dataType, parameter.Direction);

            return parameterText;
        }

        /// <summary>
        /// Generates the column text.
        /// </summary>
        /// <param name="column">The column.</param>
        /// <returns></returns>
        public static string GenerateColumnText(SD.Column column)
        {
            string columnText;
            string isNullable;
            string dataType;

            isNullable = column.IsNullable ? IsNullableValue : IsNotNullableValue;

            if(column.DbDataType.ProviderType == SD.DatabaseType.Char ||
                column.DbDataType.ProviderType == SD.DatabaseType.NChar ||
                column.DbDataType.ProviderType == SD.DatabaseType.NVarChar ||
                column.DbDataType.ProviderType == SD.DatabaseType.VarChar)
            {
                dataType = string.Format(CultureInfo.CurrentCulture, Resources.GenerateParameterTextTwoParams, column.DbDataType.ProviderType, GetColumnSize(column.DbDataType.Size));
            }
            else
            {
                dataType = column.DbDataType.ProviderType.ToString();
            }

            if(!column.IsPrimaryKey)
            {
                columnText = string.Format(CultureInfo.CurrentCulture, Resources.GenerateParameterTextThreeParams, column.Name, dataType, isNullable);
            }
            else
            {
                columnText = string.Format(CultureInfo.CurrentCulture, Resources.GenerateParameterTextThreeParamsPk, column.Name, dataType, isNullable);
            }

            return columnText;
        }

        private static string GetColumnSize(int size)
        {
            if(size == int.MaxValue)
            {
                return Resources.MAXConstant;
            }
            else
            {
                return size.ToString(NumberFormatInfo.CurrentInfo);
            }
        }
    }
}
